package com.atguigu.gmall.activity.service.impl;

import com.atguigu.gmall.activity.mapper.CouponUseMapper;
import com.atguigu.gmall.activity.service.ActivityInfoService;
import com.atguigu.gmall.activity.service.ActivityService;
import com.atguigu.gmall.activity.service.CouponInfoService;
import com.atguigu.gmall.common.execption.GmallException;
import com.atguigu.gmall.common.result.ResultCodeEnum;
import com.atguigu.gmall.model.activity.ActivityRule;
import com.atguigu.gmall.model.activity.CouponInfo;
import com.atguigu.gmall.model.activity.CouponUse;
import com.atguigu.gmall.model.cart.CartInfo;
import com.atguigu.gmall.model.cart.CartInfoVo;
import com.atguigu.gmall.model.enums.CouponStatus;
import com.atguigu.gmall.model.order.OrderDetail;
import com.atguigu.gmall.model.order.OrderDetailVo;
import com.atguigu.gmall.model.order.OrderTradeVo;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author atguigu-mqx
 */
@Service
public class ActivityServiceImpl implements ActivityService {

    //  注入活动规则，优惠券服务
    @Autowired
    private ActivityInfoService activityInfoService;

    @Autowired
    private CouponInfoService couponInfoService;

    @Autowired
    private CouponUseMapper couponUseMapper;


    @Override
    public Map<String, Object> findActivityAndCoupon(Long skuId, Long userId) {
        HashMap<String, Object> map = new HashMap<>();
        //  根据skuId 获取活动促销规则列表！
        List<ActivityRule> activityRuleList = activityInfoService.findActivityRule(skuId);

        //  根据skuId,userId 获取优惠券列表！
        List<CouponInfo> couponInfoList = couponInfoService.findCouponInfo(skuId, userId);

        map.put("activityRuleList",activityRuleList);
        map.put("couponInfoList",couponInfoList);
        //  返回map 集合数据！
        return map;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void getCouponInfo(Long couponId, String userId) {
        //  加入锁！
        Lock lock = new ReentrantLock();
        try {
            /*
            1.  根据这个优惠券Id 获取优惠券对象
            2.  判断是否可以利用这个优惠券
            3.  判断这个用户是否已经领用过
            4.  更新优惠券剩余个数
            5.  直接插入数据
             */
            //  上锁
            lock.lock();
            CouponInfo couponInfo = this.couponInfoService.getById(couponId);
            //  判断是否可以领用
            if (couponInfo.getTakenCount()>couponInfo.getLimitNum()){
                //  不能领用
                throw new GmallException(ResultCodeEnum.COUPON_LIMIT_GET);
            }
            //  判断这个用户是否已经领用过！
            //  select count(*) from coupon_use where coupon_id = ? and user_id = ?;
            QueryWrapper<CouponUse> couponUseQueryWrapper = new QueryWrapper<>();
            couponUseQueryWrapper.eq("coupon_id",couponId);
            couponUseQueryWrapper.eq("user_id",userId);
            Integer count = couponUseMapper.selectCount(couponUseQueryWrapper);

            //  判断
            if(count>0){
                throw new GmallException(ResultCodeEnum.COUPON_GET);
            }

            //  更新优惠券剩余个数
            int takenCount = couponInfo.getTakenCount().intValue()+1;
            couponInfo.setTakenCount(takenCount);
            this.couponInfoService.updateById(couponInfo);

            //  直接插入数据
            CouponUse couponUse = new CouponUse();
            couponUse.setCouponId(couponId);
            couponUse.setUserId(Long.parseLong(userId));
            couponUse.setCouponStatus(CouponStatus.NOT_USED.name());
            couponUse.setGetTime(new Date());
            couponUse.setExpireTime(couponInfo.getExpireTime());
            couponUseMapper.insert(couponUse);
        } catch (GmallException e) {
            e.printStackTrace();
        } catch (NumberFormatException e) {
            e.printStackTrace();
        } finally {
            //  解锁
            lock.unlock();
        }
    }

    @Override
    public List<CartInfoVo> findCartActivityAndCoupon(List<CartInfo> cartInfoList, Long userId) {
        //   findCartActivityRuleMap();
        //   获取优惠券 findCartCouponInfo(cartInfoList,skuIdToActivityIdMap,userId)
        //  声明一个集合
        Map<Long, Long> skuIdToActivityIdMap = new HashMap<>();
        //  skuIdToActivityIdMap 这个集合有数据了！
        //  获取到有活动的促销列表规则集合！
        List<CartInfoVo> cartInfoVoList = activityInfoService.findCartActivityRuleMap(cartInfoList, skuIdToActivityIdMap);

        //  获取到优惠券规则列表
        //  key = skuId value = List<CouponInfo>
        Map<Long, List<CouponInfo>> skuIdToCouponInfoListMap = couponInfoService.findCartCouponInfo(cartInfoList, skuIdToActivityIdMap, userId);

        //  获取到一个没有活动的促销列表集合！
        List<CartInfo> noJoinCartInfoList = new ArrayList<>();
        //  循环遍历cartInfoList ： 这个集合列表中，有skuId 是有参与活动的，也有skuId 是没有参与活动的！
        for (CartInfo cartInfo : cartInfoList) {
            //  skuIdToActivityIdMap 存储的数据 key = skuId value = activityId;
            if (!skuIdToActivityIdMap.containsKey(cartInfo.getSkuId())){
                //  表示获取到了没有参与活动的购物项
                noJoinCartInfoList.add(cartInfo);
            }
        }

        //  判断 noJoinCartInfoList 表示没有参与活动的购物项数据
        if (!CollectionUtils.isEmpty(noJoinCartInfoList)){
            //  声明一个对象
            CartInfoVo cartInfoVo = new CartInfoVo();
            //  将没有参与活动购物项集合添加到cartInfoVo 对象中
            cartInfoVo.setCartInfoList(noJoinCartInfoList);
            //  将活动规则集合赋值为空
            cartInfoVo.setActivityRuleList(null);

            //  将没有参与活动的carInfoVo 添加到集合中
            cartInfoVoList.add(cartInfoVo);
        }

        //  处理优惠券列表的显示！
        for (CartInfoVo cartInfoVo : cartInfoVoList) {
            //  获取到对应的购物项列表集合
            List<CartInfo> cartInfoList1 = cartInfoVo.getCartInfoList();
            //  循环遍历
            for (CartInfo cartInfo : cartInfoList1) {
                //  这个对象中要赋值优惠券列表集合
                cartInfo.setCouponInfoList(skuIdToCouponInfoListMap.get(cartInfo.getSkuId()));
            }
        }
        //  返回数据
        return cartInfoVoList;
    }

    @Override
    public OrderTradeVo findTradeActivityAndCoupon(List<OrderDetail> orderDetailList, Long userId) {
        //  声明一个对象
        OrderTradeVo orderTradeVo = new OrderTradeVo();
        //  private List<OrderDetailVo> orderDetailVoList; 订单明细
        //  private BigDecimal activityReduceAmount; 促销优惠金额
        //  private List<CouponInfo> couponInfoList; 订单优惠券列表

        //  数据准备
        Map<Long, OrderDetail> skuIdToOrderDetailMap = new HashMap<>();
        for (OrderDetail orderDetail : orderDetailList) {
            //  key skuId value orderDetail;
            skuIdToOrderDetailMap.put(orderDetail.getSkuId(),orderDetail);
        }

        //  OrderDetailVo : orderDetailList, activityRule
        //  key = activityId value = ActivityRule
        Map<Long, ActivityRule> activityIdToActivityRuleMap = activityInfoService.findTradeActivityRuleMap(orderDetailList);
        //  声明一个对象
        List<OrderDetailVo> orderDetailVoList = new ArrayList<>();

        //  声明一个集合来存储活动的skuId
        List<Long> activityIdSkuId = new ArrayList<>();

        //  促销优惠的金额变量
        BigDecimal activityReduceAmount = new BigDecimal("0");
        //  循环遍历
        Iterator<Map.Entry<Long, ActivityRule>> iterator = activityIdToActivityRuleMap.entrySet().iterator();
        while (iterator.hasNext()){
            //  获取里面的数据
            Map.Entry<Long, ActivityRule> entry = iterator.next();
            ActivityRule activityRule = entry.getValue();

            //  声明一个OrderDetailList 集合
            List<OrderDetail> detailList = new ArrayList<>();
            //  获取到活动规则下的skuId 集合
            List<Long> skuIdList = activityRule.getSkuIdList();
            //  循环遍历
            for (Long skuId : skuIdList) {
                //  通过skuId 获取到 orderDetail
                OrderDetail orderDetail = skuIdToOrderDetailMap.get(skuId);
                //  当前这个活动Id 下对应的订单明细！
                detailList.add(orderDetail);
            }
            //  获取到优惠后的总金额！
            activityReduceAmount = activityReduceAmount.add(activityRule.getReduceAmount());
            //  声明一个对象
            OrderDetailVo orderDetailVo = new OrderDetailVo();
            //  赋值订单明细集合
            orderDetailVo.setOrderDetailList(detailList);
            orderDetailVo.setActivityRule(activityRule);

            //  将每次循环获取到的orderDetailVo 放入集合
            orderDetailVoList.add(orderDetailVo);
            //  将活动的skuId 进行保存！
            activityIdSkuId.addAll(skuIdList);
        }

        //  声明一个集合来存储没有活动的数据
        List<OrderDetail> detailList = new ArrayList<>();
        //  没有活动的如何获取orderDetail
        //  skuIdList --- 这个表示有活动的skuId列表 orderDetailList ---- 这个表示有活动的skuId ，还有没有参与活动的skuId！
        //  循环遍历
        for (OrderDetail orderDetail : orderDetailList) {
            if (!activityIdSkuId.contains(orderDetail.getSkuId())){
                //  说明这个skuId 没有参与活动！
                detailList.add(skuIdToOrderDetailMap.get(orderDetail.getSkuId()));
            }
        }
        // 创建一个对象
        OrderDetailVo orderDetailVo = new OrderDetailVo();
        orderDetailVo.setOrderDetailList(detailList);
        orderDetailVo.setActivityRule(null);
        //  将没有参与活动的orderDetailVo 添加到这个集合
        orderDetailVoList.add(orderDetailVo);

        //  第一个属性赋值！
        orderTradeVo.setOrderDetailVoList(orderDetailVoList);

        //  第二个属性赋值！
        orderTradeVo.setActivityReduceAmount(activityReduceAmount);

        //  第三个属性赋值！
        //  调用方法
        List<CouponInfo> couponInfoList = couponInfoService.findTradeCouponInfo(orderDetailList, activityIdToActivityRuleMap, userId);
        orderTradeVo.setCouponInfoList(couponInfoList);

        //  返回数据
        return orderTradeVo;
    }
}
